package com.Touch.TouchSimulator
{
	import com.Events.SimTouchEvent;
	
	import flash.display.Bitmap;
	import flash.display.DisplayObject;
	import flash.display.Stage;
	import flash.events.DataEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.geom.Point;
	import flash.net.XMLSocket;
	import flash.utils.setTimeout;
	
	public class TUIOTouchSupport extends EventDispatcher
	{
		
		//-----------------------------------------------------
		/*              单例模式与静态                        */
		//-----------------------------------------------------
		private static var tts:TUIOTouchSupport;
		public static function getTuioTouchSupport():TUIOTouchSupport{
			if(tts==null){
				tts=new TUIOTouchSupport();
			}
			return tts;
		}
		
		public static function init(_stage:Stage,_ip:String="127.0.0.1",_port:int=3000):void{
			getTuioTouchSupport().init(_stage,_ip,_port);
		}
		//------------------------------------------------------
		
		
		private var tuioSocket:XMLSocket;
		
		private var tuioHost:String;
		
		private var tuioPort:int;//连接的端口
		
		private var reTry:int;//当前重试次数计数
		
		private var maxReTry:int=3;//连续重试次数最大值  当超过此值时报错
		
		private var touchlist:Vector.<SimulateTouchAppliedObj>;//用于储存触摸点的数组
		
		private var stage:Stage;
		
		private var stageWidth:int;
		
		private var stageHeight:int;
		
		//--------------------------------------------------------------------
		/*                      通用  外部接口                               */
		//--------------------------------------------------------------------
		public function TUIOTouchSupport()
		{
			super();
			touchlist=new Vector.<SimulateTouchAppliedObj>();
			tuioSocket=new XMLSocket();
			tuioSocket.addEventListener(Event.CONNECT,connectHandler);
			tuioSocket.addEventListener(Event.CLOSE,closeHandler);
			tuioSocket.addEventListener(IOErrorEvent.IO_ERROR,ioErrorHandler);
			tuioSocket.addEventListener(DataEvent.DATA,dataHandler);
		}
		
		public function init(_stage:Stage,_ip:String="127.0.0.1",_port:int=3000):void{
			stage=_stage;
			stageWidth=stage.stageWidth;
			stageHeight=stage.stageHeight;
			tuioHost=_ip;
			tuioPort=_port;
			reTry=0;
			connect();
		}
		//------------------------------------------------------------------------
		
		private function connect():void{
			if(tuioSocket.connected){
				return;
			}
			reTry++;
			if(reTry>maxReTry){
				var events:SimTouchEvent=new SimTouchEvent(SimTouchEvent.TUIO_INFO);
				events.msg="CONNECT_FAILED";
				this.dispatchEvent(events);
				return;
			}
			tuioSocket.connect(tuioHost,tuioPort);
		}
		
		private function processMessage(msg:XML):void{
			var node:XML;
			var fseq:int;
			
			//trace(msg);
			
			//可感知用户界面配置
			for each(node in msg.MESSAGE)
			{
				if(node.ARGUMENT[0] && node.ARGUMENT[0].@VALUE == "fseq")
					fseq = int(node.ARGUMENT[1].@VALUE);
			}
			
			//点是否存在
			for each(node in msg.MESSAGE)
			{
				if(node.ARGUMENT[0].@VALUE == "alive")
				{
					
					for each (var obj:SimulateTouchAppliedObj in touchlist)
					{
						obj.isExist=false;
					}
					
					for each(var aliveItem:XML in node.ARGUMENT.(@VALUE != "alive"))
					{
						var temp:SimulateTouchAppliedObj=isexist(int(aliveItem.@VALUE));
						if(temp!=null){
							temp.isExist=true;
						}
					}
				}
			}
			// 处理set消息				
			for each(node in msg.MESSAGE)
			{
				if(node.ARGUMENT[0])
				{
					if(node.@NAME == "/tuio/2Dcur")
					{
						var type:String = node.ARGUMENT[0].@VALUE;		
						if(type == "set") 
						{
							var local_id:int = int(node.ARGUMENT[1].@VALUE);
							var x:Number = Number(node.ARGUMENT[2].@VALUE) * stageWidth;
							var y:Number = Number(node.ARGUMENT[3].@VALUE) * stageHeight;							
							
							//获取点下舞台元素
							var disobj:DisplayObject=null;
							var objArray:Array = stage.getObjectsUnderPoint(new Point(x, y));
							if(objArray.length>0){
								disobj=objArray[objArray.length-1];
								if(disobj is Bitmap){
									disobj=disobj.parent;
								}
							}						
							
							//查找实例
							var tempobj:SimulateTouchAppliedObj=isexist(local_id);
							
							//如果没有这个点则新建一个点
							if(tempobj==null){
								//取得没有被占用的触摸点值
								var id:int=CreatePoint();
								if(id>0){
									tempobj=new SimulateTouchAppliedObj(id,stage,"",local_id);
									tempobj.TouchOn(x,y,disobj);
									touchlist.push(tempobj);
								}else{
									return;//超过点数上限
								}
							}else{
								tempobj.TouchMove(x,y,disobj);
							}
						}
					}
				}
			}
			for(var k:int=touchlist.length-1;k>=0;k--){
				if(!touchlist[k].isExist){
					touchlist[k].TouchRemove();
					touchlist.splice(k,1);
				}
			}
		}
		
		//检查是否存在点
		private function isexist(_id:int):SimulateTouchAppliedObj{
			for each(var temp:SimulateTouchAppliedObj in touchlist){
				if(temp.local_id==_id){
					return temp;
				}
			}
			return null;
		}
		
		//创建一个新点
		private function CreatePoint():int{
			for(var i:int=192;i<255;i++){
				var has:Boolean=false;//判断此序列是否在列表中存在
				for each(var temp:SimulateTouchAppliedObj in touchlist){
					if(i==temp.id){
						has=true;
					}
				}
				if(!has){//如果不存在则返回
					return i;
				}
			}
			return -1;//超过上限则取消
		}
		
		//--------------------------------------------------------------------
		/*                      socket事件处理                              */
		//--------------------------------------------------------------------
		private function closeHandler(event:Event):void {
			var events:SimTouchEvent=new SimTouchEvent(SimTouchEvent.TUIO_INFO);
			events.msg="SERVER_CLOSED";
			this.dispatchEvent(events);
		}
		private function connectHandler(event:Event):void {
			var events:SimTouchEvent=new SimTouchEvent(SimTouchEvent.TUIO_INFO);
			events.msg="CONNECT_SUCCEED";
			this.dispatchEvent(events);
			reTry=0;
		}
		private function dataHandler(event:DataEvent):void {
			processMessage(XML(event.data));
		}
		private function ioErrorHandler(event:IOErrorEvent):void {
			setTimeout(connect,100);
		}
		private function securityErrorHandler(event:SecurityErrorEvent):void {
			//event
		}
		//----------------------------------------------------------------------
	}
}